/** 
 * @file Node.h 
 * 
 * @brief  Node 
 * @author Bas du Pre
 * @date   19-05-2011
 *
 * @details Bla
 * 
 **/ 

#pragma once

namespace Prism {
namespace Graphics {
    class Node;
}
}

#include "../global.h"
#include "../Events.h"
#include "Touch.h"

namespace Prism {
namespace Graphics {
    
    class UpdateEventArgs : public EventArgs {        
    public:
        UpdateEventArgs(PFloat delta) : delta(delta) { }
        PFloat delta;
    };
    
    class Node : public PObject {
        
        friend class Director;
        
    public:
        Node();
        virtual ~Node();
                
        void addChild(Node *node);
        void addChild(Node *node, PInt z);
        void addChild(Node *node, PInt z, PInt tag);
        void removeChild(Node *node);
        void removeChildByTag(PInt tag);
        void removeAllChildren();
        List<Node*> getChildrenByTag(PInt tag);
        void reorderChild(Node *child, PInt z);
        List<Node*> getChildren();
       
        virtual Rect boundingBox();
        
        /*Action *runAction(Action *action);
        void stopAllActions();
        void stopAction(Action *action);
        Action *getActionByTag(int tag);
        int numberOfRunningActions();*/
        
        virtual void draw(); 
        
        // Properties
        virtual void setZOrder(PInt z);
        virtual PInt zOrder();
        virtual void setRotation(PFloat rotation);
        virtual PFloat rotation();
        virtual void setScale(PFloat scale);
        virtual PFloat scale();
        virtual void setScaleX(PFloat scaleX);
        virtual PFloat scaleX();
        virtual void setScaleY(PFloat scaleY);
        virtual PFloat scaleY();
        virtual void setPosition(PointF position);
        virtual void setPosition(PFloat x, PFloat y);
        virtual PointF position();
        virtual void setVisible(bool visible);
        virtual bool visible();
        virtual void setAnchorPoint(PointF anchorPoint);
        virtual void setAnchorPoint(PFloat x, PFloat y);
        virtual PointF anchorPoint();
        virtual Node *parent();
        virtual bool hasParent();
        virtual void setParent(Node* parent);
        virtual void setIsRelativeAnchorPoint(bool isRelativeAnchorPoint);
        virtual bool isRelativeAnchorPoint();
        virtual void setTag(PInt tag);
        virtual PInt tag();
        virtual void setUserData(void *userData);
        virtual void *userData();
        
        virtual PointF screenPosition();
        virtual PFloat screenRotation();
        virtual PFloat screenScaleX();
        virtual PFloat screenScaleY();
        PInt screenZ();
        
        virtual List<Node*> hitTest(PointF point, bool shouldSort = true);
        virtual bool coversPoint(PointF point);
        
        virtual String toString();
        
        static bool compareByZOrder(Node *a, Node *b);
        static bool compareByScreenZOrder(Node *a, Node *b);
        
        // Events        
        //Event<EventArgs*> onEnter;
        //Event<EventArgs*> onExit;
        Event<UpdateEventArgs*> onUpdate;
        Event<EventArgs*> onScaleChange;
        Event<EventArgs*> onRotationChange;
        Event<EventArgs*> onZOrderChange;
        Event<EventArgs*> onPositionChange;
        Event<EventArgs*> onVisibleChange;
        Event<EventArgs*> onAnchorPointChange;
        Event<EventArgs*> onParentChange;
        Event<EventArgs*> onIsRelativeAnchorPointChange;
        Event<EventArgs*> onTagChange;
        Event<EventArgs*> onUserDataChange;
        
        Event<TouchEventArgs*> onTap;
        Event<TouchEventArgs*> onDoubleTap;
        Event<TouchesEventArgs*> onTouchesBegan;
        Event<TouchesEventArgs*> onTouchesEnded;
        Event<TouchesEventArgs*> onTouchesMoved;
        
        #if PRISM_OS_IOS && PRISM_BUILDENGINE
        #include "iOS/ios_Node.h"
        #elif PRISM_TARGET_SDL
        #include "sdl/sdl_Node.h"
        #endif
        
    protected:
        void visit();
        virtual void native_visit();
        
        PInt _z;
        
    private:
        void sortChildren();
        
        bool _shouldSortChildren;
        PointF _scale;
        PFloat _rotation;
        List<Node*> _childs;
        bool _visible;
        PointF _position;
        PointF _anchorPoint;
        Node* _parent;
        bool _isRelativeAnchorPoint;
        PInt _tag;
        void* _userData;
        PInt _screenZ;
        
        static PInt _staticScreenZ;
        static PInt getNextZ();
    };
}
}
